package com.hp.bon.sgw.wh.mml.handler;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.wh.mml.MMLEncoder;
import com.hp.bon.sgw.wh.mml.common.MMLConstants;
import com.hp.bon.sgw.wh.mml.common.MMLSessionEntity;
import com.hp.bon.sgw.wh.mml.common.MMLSessionIdUtils;
import com.hp.bon.sgw.wh.mml.common.MMLUtils;
import com.hp.bon.sgw.wh.mml.common.MsgUtils;
import com.hp.bon.sgw.wh.mml.helper.LogMsgHelper;
import com.hp.bon.sgw.wh.mml.repositories.PropertyRepository;
import com.hp.bon.sgw.wh.mml.repositories.VCMsgRelayRepository;
import com.hp.bon.sgw.wh.mml.repositories.VCMsgRepository;

import ch.unifr.nio.framework.transform.ChannelWriter;
import ch.unifr.nio.framework.transform.StringToByteBufferTransformer;

public class MMLOutputHandler extends Thread {
	
	private static final Logger logger = LoggerFactory.getLogger(MMLOutputHandler.class);

	private final StringToByteBufferTransformer transformer;

	public MMLOutputHandler(ChannelWriter writer) {
		setDaemon(false);
		// setup output transformation chain:
		// stringToByteBuffer -> writer
		transformer = new StringToByteBufferTransformer();
		transformer.setNextForwarder(writer);
	}

	@Override
	public void run() {
		logger.info("VCClient is running...");
		while (true) {
			
			//0. process VC Heart Beat Message
			boolean haveHeartBeat = echoVCHeartBeat();			
			//1. process login package
			boolean hasLoginMsg = sendVCLoginMsg();			
			//2. process transaction package
			boolean hasTransactionMsg = sendVCTransactionMsg();			
			//3. process logout package
			boolean hasVCLogoutMsg = sendVCLogoutMsg();
			
			if (!haveHeartBeat && !hasLoginMsg && !hasTransactionMsg && !hasVCLogoutMsg) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					logger.warn("MMLOutputHandler", e);
					e.printStackTrace();
				}
				continue;
			}
		}
	}
	
	private boolean echoVCHeartBeat(){
		//0. process VC Heart Beat Message
		String vcHeartBeatMsg = VCMsgRepository.pollVCHeartBeatMsg();
		if(vcHeartBeatMsg!=null){
			try {
				logger.info("--------------ack vc heartbeat start--------------");
				logger.info("-- " + vcHeartBeatMsg);
				vcHeartBeatMsg += "\r\n";
				transformer.forward(vcHeartBeatMsg);
				logger.info("--------------ack vc heartbeat end----------------");
			} catch (IOException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			}
			return true;
		}
		return false;
	}
	
	private boolean sendVCLoginMsg(){
		boolean hasMsg = false;
		//1. process login package
		MMLSessionEntity loginEntity = VCMsgRepository.pollXmlMsg();
		if(loginEntity!=null){
			String sessionId = MMLUtils.formatSessionId(MMLSessionIdUtils.genSessionId());
			VCMsgRelayRepository.put(sessionId, loginEntity);
			loginEntity.setSessionId(sessionId);
			String termIdentity = PropertyRepository.getTermIdentity();
			String user = PropertyRepository.getUserId();
			String password = PropertyRepository.getPassword();
			String mmlCommand = MMLEncoder.buildMMLLoginCommand(user, password);
			String packageInfo = null;
			try {
				packageInfo = MMLEncoder.buildMMLLoginPackage(sessionId, 1, termIdentity, mmlCommand);
				LogMsgHelper.appendLogMsg(packageInfo);
				transformer.forward(packageInfo);
			} catch (NumberFormatException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (IOException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			}
			hasMsg = true;			
			logger.info("Sending VC Login MML Message:");			
			logger.info(packageInfo);
		}
		return hasMsg;
	}
	
	private boolean sendVCTransactionMsg(){
		boolean hasTransactionMsg = false;
		//2. process transaction package
		MMLSessionEntity transactionEntity = VCMsgRepository.pollVCMsg();
		if(transactionEntity!=null){
			String capName = MsgUtils.getCapabilityName(transactionEntity.getXmlMsg().getSCID());
			String sessionId = transactionEntity.getSessionId();
			String termIdentity = PropertyRepository.getTermIdentity();
			String mmlCommandData = transactionEntity.getXmlMsg().getDATA();
			String mmlCommand = MMLEncoder.buildMMLTransactionCommand(capName, mmlCommandData);
			String packageInfo = null;
			try {
				packageInfo = MMLEncoder.buildMMLTransactionPackage(
						sessionId, 2, termIdentity, mmlCommand, 
						MMLConstants.MML_SESSION_CONNECTION,
						PropertyRepository.getMMLLanguage());
				LogMsgHelper.appendLogMsg(packageInfo);					
				transformer.forward(packageInfo);
			} catch (NumberFormatException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (IOException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			}
			hasTransactionMsg = true;
			logger.info("Sending VC transaction MML Message:");		
			logger.info(packageInfo);
		}
		return hasTransactionMsg;
	}

	private boolean sendVCLogoutMsg(){
		boolean hasVCLogoutMsg = false;
		//3. process logout package
		MMLSessionEntity logoutEntity = VCMsgRepository.pollLogoutMsg();
		if(logoutEntity!=null){
			String sessionId = logoutEntity.getSessionId();
			//VCMsgRelayRepository.remove(sessionId);
			String termIdentity = PropertyRepository.getTermIdentity();
			String user = PropertyRepository.getUserId();
			String password = PropertyRepository.getPassword();
			String mmlCommand =  MMLEncoder.buildMMLLogoutCommand(user, password);
			String packageInfo = null;
			try {
				packageInfo = MMLEncoder.buildMMLLogoutPackage(sessionId, 3, termIdentity, mmlCommand);
				LogMsgHelper.appendLogMsg(packageInfo);	
				transformer.forward(packageInfo);
			} catch (NumberFormatException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			} catch (IOException e) {
				logger.warn("MMLOutputHandler", e);
				e.printStackTrace();
			}
			hasVCLogoutMsg = true;
			logger.info("Sending VC logout MML Message:");			
			logger.info(packageInfo);
		}
		return hasVCLogoutMsg;
	}
}
